import {
  Body,
  Controller,
  Get,
  Param,
  Headers,
  Query,
  Post,
  Put,
  Delete,
  UseInterceptors,
  ClassSerializerInterceptor,
  Session,
  UploadedFile,
  StreamableFile,
} from '@nestjs/common';
import {
  ApiBearerAuth,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
import { ILike, In } from 'typeorm';
import { FileInterceptor } from '@nestjs/platform-express';
import { genSalt, hash, compare } from 'bcryptjs';
import { IsAuth } from 'src/decorators/auth.decorator';
import { IResponseData, responseData } from 'src/utils/result';
import {
  CreateUserDto,
  FindUserListDto,
  ResetUserPwdDto,
  UpdateUserDto,
  UpdateUserPwdDto,
  UserDto,
} from './user.dto';
import { UserService } from './user.service';
import { getIdLists } from 'src/utils/dataAuth';
import { UploadDto } from '../common/common.dto';
import { checkType } from 'src/utils/tools';

@ApiTags('用户模块')
@ApiBearerAuth()
@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @ApiOperation({ summary: '查询用户列表' })
  @ApiResponse({
    status: 200,
    description: '查询用户列表',
    type: UserDto,
  })
  @UseInterceptors(ClassSerializerInterceptor)
  @Get()
  @IsAuth('system:user:list')
  async findList(
    @Query() dto: FindUserListDto,
    @Session() session,
    @Headers() headers,
  ): Promise<IResponseData> {
    const roles =
      dto.roles &&
      dto.roles.split(',').map((id) => ({
        id: parseInt(id),
      }));
    let deptIds: any;
    if (dto.deptId) {
      deptIds = getIdLists(
        session.departmentsObj.obj[dto.deptId].children,
        [dto.deptId],
        'id',
      );
    } else {
      if (session.userInfo.dept) {
        deptIds = getIdLists(
          session.departmentsObj.obj[session.userInfo.dept.id].children,
          [session.userInfo.dept.id],
          'id',
        );
      }
    }
    delete dto.deptId;
    const where = {
      ...dto,
      is_delete: '0',
      user_name: dto.user_name ? ILike('%' + dto.user_name + '%') : null,
      roles,
      dept: deptIds ? In(deptIds) : null,
    };
    const res = await this.userService.getLists({
      where,
      relations: ['roles', 'dept', 'position'],
    });
    return responseData({
      code: 100010,
      data: res,
      language: headers['language'],
    });
  }

  @ApiOperation({ summary: '查询用户信息' })
  @ApiResponse({
    status: 200,
    description: '查询用户信息',
  })
  @UseInterceptors(ClassSerializerInterceptor)
  @Get('getInfo')
  @IsAuth('system:user:getInfo')
  async getInfo(
    @Session() session: Record<string, any>,
    @Headers() headers,
  ): Promise<IResponseData> {
    const result = {
      permissions: session.permissions,
      user: session.userInfo,
    };

    return responseData({
      code: 100010,
      data: result,
      language: headers['language'],
    });
  }

  @ApiOperation({ summary: '查询用户详情' })
  @ApiResponse({
    status: 200,
    description: '查询用户详情',
    type: UserDto,
  })
  @UseInterceptors(ClassSerializerInterceptor)
  @Get(':id')
  @IsAuth('system:user:detail')
  async find(
    @Param('id') id: number,
    @Headers() headers,
  ): Promise<IResponseData> {
    const res = await this.userService.getOne({
      relations: ['roles', 'dept', 'position'],
      where: {
        id,
      },
    });
    return responseData({
      code: 100010,
      data: res,
      language: headers['language'],
    });
  }

  @Post()
  @IsAuth('system:user:add')
  @ApiOperation({ summary: '创建用户' })
  @ApiResponse({ status: 200, description: '操作成功' })
  async create(
    @Body() dto: CreateUserDto,
    @Headers() headers,
  ): Promise<IResponseData> {
    const salt = await genSalt();
    dto.password = await hash(dto.password, salt);
    const lists = dto.roles.join(',').split(',');
    dto.roles = lists.map((id) => ({
      id: parseInt(id),
    }));
    const res = await this.userService.create(dto);
    return responseData({
      code: 100020,
      data: res,
      language: headers['language'],
    });
  }

  @Put()
  @IsAuth('system:user:update')
  @ApiOperation({ summary: '更新用户' })
  @ApiResponse({ status: 200, description: '操作成功' })
  async update(
    @Body() dto: UpdateUserDto,
    @Headers() headers,
  ): Promise<IResponseData> {
    if (dto.roles) {
      const lists = dto.roles.join(',').split(',');
      dto.roles = lists.map((id) => ({
        id: parseInt(id),
      }));
    }

    const res = await this.userService.update(dto);
    return responseData({
      code: 100030,
      data: res,
      language: headers['language'],
    });
  }

  @Put('updatePwd')
  @IsAuth('system:user:updatePwd')
  @ApiOperation({ summary: '修改密码' })
  @ApiResponse({ status: 200, description: '操作成功' })
  async updatePwd(
    @Body() dto: UpdateUserPwdDto,
    @Headers() headers,
  ): Promise<IResponseData> {
    const user: UserDto = await this.userService.getOne({
      where: {
        id: dto.id,
      },
    });
    const checkPassword = await compare(dto.oldPassword, user.password);
    if (!checkPassword) throw new Error('密码错误');
    const salt = await genSalt();
    dto.password = await hash(dto.password, salt);
    delete dto.oldPassword;
    const res = await this.userService.update(dto);
    return responseData({
      code: 100030,
      data: res,
      language: headers['language'],
    });
  }

  @Put('resetPwd')
  @IsAuth('system:user:resetPwd')
  @ApiOperation({ summary: '重置密码' })
  @ApiResponse({ status: 200, description: '操作成功' })
  async resetPwd(
    @Body() dto: ResetUserPwdDto,
    @Headers() headers,
  ): Promise<IResponseData> {
    const salt = await genSalt();
    dto.password = await hash(dto.password, salt);
    const res = await this.userService.update(dto);
    return responseData({
      code: 100030,
      data: res,
      language: headers['language'],
    });
  }

  @Delete()
  @IsAuth('system:user:delete')
  @ApiOperation({ summary: '删除用户' })
  @ApiResponse({ status: 200, description: '操作成功' })
  async delete(
    @Query('ids') query: string,
    @Headers() headers,
  ): Promise<IResponseData> {
    const res = await this.userService.update_delete(query);
    return responseData({
      code: 100040,
      data: res,
      language: headers['language'],
    });
  }

  @UseInterceptors(FileInterceptor('file'))
  @ApiConsumes('multipart/form-data')
  @Post('importExcel')
  @IsAuth('system:user:importExcel')
  @ApiOperation({ summary: '用户导入' })
  @ApiResponse({ status: 200, description: '操作成功' })
  async importExcel(
    @UploadedFile() file: Express.Multer.File,
    @Body() body: UploadDto,
    @Headers() headers,
  ): Promise<IResponseData> {
    const userLists = await this.userService.importExcel(file);
    console.log(body);
    const salt = await genSalt();
    const password = await hash('123456', salt);
    for (let i = 0; i < userLists.length; i++) {
      if (checkType.isString(userLists[i].roles)) {
        const lists = userLists[i].roles.split(',');
        userLists[i].roles = lists.map((id) => ({
          id: parseInt(id),
        }));
      } else {
        userLists[i].roles = [
          {
            id: userLists[i].roles,
          },
        ];
      }
      userLists[i].password = password;
      userLists[i].dept = {
        id: userLists[i].dept,
      };
      userLists[i].sex = userLists[i].sex === '男' ? '1' : '0';
    }
    await this.userService.importUser(userLists);
    return responseData({
      code: 0,
      language: headers['language'],
    });
  }

  @Post('exportExcelTemplate')
  @ApiOperation({ summary: '用户导出模板' })
  @ApiResponse({ status: 200, description: '操作成功' })
  async exportExcelTemplate(): Promise<any> {
    const columns = [
      {
        name: '用户名',
        key: 'user_name',
        width: 40,
      },
      {
        name: '昵称',
        key: 'nick_name',
        width: 40,
      },
      {
        name: '性别',
        key: 'sex',
        width: 40,
      },
      {
        name: '角色id',
        key: 'roles',
        width: 40,
      },
      {
        name: '部门id',
        key: 'dept',
        width: 40,
      },
    ];
    const exportdata = [
      {
        sheet: 'sheet1',
        rows: [['test', '测试', '男', '1', '1']],
        columns,
      },
    ];
    const buffer = await this.userService.exportExcel(exportdata);
    return new StreamableFile(buffer);
  }

  @Post('exportExcel')
  @IsAuth('system:user:exportExcel')
  @ApiOperation({ summary: '用户导出' })
  @ApiResponse({ status: 200, description: '操作成功' })
  async exportExcel(): Promise<any> {
    const { lists } = await this.userService.getAll();
    const columns = [
      {
        name: '用户名',
        key: 'user_name',
        width: 40,
      },
      {
        name: '昵称',
        key: 'user_name',
        width: 40,
      },
      {
        name: '性别',
        key: 'sex',
        width: 40,
      },
      {
        name: '邮箱',
        key: 'email',
        width: 40,
      },
      {
        name: '手机号码',
        key: 'phone',
        width: 40,
      },
    ];
    const rows = [];
    lists.forEach((item) => {
      const row = [];
      columns.forEach((list) => {
        if (list.key === 'sex') {
          row.push(item[list.key] === '1' ? '男' : '女');
        } else {
          row.push(item[list.key]);
        }
      });
      rows.push(row);
    });

    const exportdata = [
      {
        sheet: 'sheet1',
        rows,
        columns,
      },
    ];

    const buffer = await this.userService.exportExcel(exportdata);
    return new StreamableFile(buffer);
  }
}
